import tkinter as tk
import threading
from time import sleep
import ctypes
from ctypes import wintypes
from playsound3 import playsound
import subprocess
import sys
import os
import xml.etree.ElementTree as ET

import platform

"""
Windows/Linux平台电池检测及监控
"""

sysplf = platform.system()

def read_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            content = file.read()
            return content[:-1]
    except FileNotFoundError:
        return None

try:
    base_path = sys._MEIPASS
except Exception:
    base_path = os.path.abspath(".")
wav_path = os.path.join(base_path, "a.wav")

if sysplf == 'Windows':
    # 定义要执行的命令
    command = "powercfg /batteryreport /output battery.xml /xml"
    # 使用subprocess模块执行命令
    with subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
        stdout, stderr = process.communicate()

    # 解析XML文件
    tree = ET.parse('battery.xml')
    root = tree.getroot()

    os.remove('battery.xml')

    # 获取命名空间URL，因为XML使用了命名空间
    namespace = root.tag[1:].split('}')[0]
    ns = {'ns': namespace}
      
    # 查找Batteries节中的Battery小节
    batteries = root.findall('ns:Batteries/ns:Battery', ns)
      
    # 遍历每个Battery小节并打印所需的值
    for battery in batteries:
        cycle_count = battery.find('ns:CycleCount', ns).text
        full_charge_capacity = battery.find('ns:FullChargeCapacity', ns).text
        design_capacity = battery.find('ns:DesignCapacity', ns).text
        manufacturer = battery.find('ns:Manufacturer', ns).text

    class SYSTEM_POWER_STATUS(ctypes.Structure):
        _fields_ = [
            ('ACLineStatus', wintypes.BYTE),
            ('BatteryFlag', wintypes.BYTE),
            ('BatteryLifePercent', wintypes.BYTE),
        ]

    GetSystemPowerStatus = ctypes.windll.kernel32.GetSystemPowerStatus
    status = SYSTEM_POWER_STATUS()

elif sysplf == 'Linux':
    for x in range(4):
        batn = '/sys/class/power_supply/BAT'+str(x)
        if os.path.exists(batn):
            break
    cycle_count = read_file(batn+'/cycle_count')
    full_charge_capacity = read_file(batn+'/energy_full')
    design_capacity = read_file(batn+'/energy_full_design')
    manufacturer = read_file(batn+'/manufacturer')


# 声明全局变量
window, cap, acst, label_cap, label_pwrst = None, 0, '', None, None

if sysplf == 'Windows':
    def start_background_task():
        global window, cap, acst
        while not window.closed:
            if not GetSystemPowerStatus(ctypes.pointer(status)):
                raise ctypes.WinError()
            if status.ACLineStatus == 1:
                acst = 'AC'
            else:
                acst = 'DC'
            cap = status.BatteryLifePercent
            #print("后台任务正在运行...")
            threading.Event().wait(0.5)  # 模拟耗时操作，这里等待0.5秒
        #print("后台任务结束.")

elif sysplf == 'Linux':
    def start_background_task():
        global window, cap, acst
        while not window.closed:
            status = read_file(batn+'/status')
            if status == 'Discharging':
                acst = 'DC'
            else:
                acst = 'AC'
            cap = read_file(batn+'/capacity')
            #print("后台任务正在运行...")
            threading.Event().wait(0.5)  # 模拟耗时操作，这里等待0.5秒
        #print("后台任务结束.")

def on_closing():
    global window
    window.closed = True
    window.destroy()

def update_label():
    global window, label_cap, label_pwrst
    label_cap.config(text=f"CAPACITY : {cap}%")
    label_pwrst.config(text=f"POWER STATUS : {acst}")
    if acst == 'AC':
        label_pwrst.config(fg="red")
    else:
        label_pwrst.config(fg="blue")
    window.after(500, update_label)  # 安排下一次更新

def play():
    playsound(wav_path)

def cap_btn_event():
    try:
        cap_ala = int(entry_cap_alarm.get())
        if cap_ala != cap:
            entry_cap_alarm.config(state="disable")
            btn_cap_alarm.config(state="disable")
            btn_cap_alarm.config(text="Running...")
            while cap_ala != cap:
                sleep(1)
            btn_cap_alarm.config(state="normal")
            btn_cap_alarm.config(text="Start")
            entry_cap_alarm.config(state="normal")
            play()
    except:
        pass

def time_btn_event():
    try:
        time_ala = int(entry_time_alarm.get())
        if time_ala > 0:
            entry_time_alarm.config(state="disable")
            btn_time_alarm.config(state="disable")
            btn_time_alarm.config(text="Running...")
            sleep(time_ala * 60)
            btn_time_alarm.config(state="normal")
            btn_time_alarm.config(text="Start")
            entry_time_alarm.config(state="normal")
            play()
    except:
        pass

def cap_btn_click():
    cap_btn_thread = threading.Thread(target=cap_btn_event)
    cap_btn_thread.daemon = True  # 设置为守护线程，当主程序退出时，自动结束线程
    cap_btn_thread.start()  # 启动线程

def time_btn_click():
    time_btn_thread = threading.Thread(target=time_btn_event)
    time_btn_thread.daemon = True  # 设置为守护线程，当主程序退出时，自动结束线程
    time_btn_thread.start()  # 启动线程

def create_window():
    global window, label_cap, label_pwrst, btn_cap_alarm, btn_time_alarm, entry_cap_alarm, entry_time_alarm
    window = tk.Tk()  # 定义root
    window.title("BatteryInfo")
    window.resizable(0, 0)
    window.closed = False
    window.protocol("WM_DELETE_WINDOW", on_closing)

    # 创建并启动后台任务的线程
    background_thread = threading.Thread(target=start_background_task)
    background_thread.daemon = True  # 设置为守护线程，当主程序退出时，自动结束线程
    background_thread.start()

    # 使用grid布局管理器
    label_cycount = tk.Label(window, text=f"CYCLE COUNT : {cycle_count}", font=("Arial", 15))
    label_cycount.grid(row=0, column=1, padx=10, pady=10)
    label_dcap = tk.Label(window, text=f"DESIGN CAPACITY : {design_capacity}", font=("Arial", 15))
    label_dcap.grid(row=1, column=0, padx=10, pady=10)
    label_fcap = tk.Label(window, text=f"FULL CHARGE CAPACITY : {full_charge_capacity}", font=("Arial", 15))
    label_fcap.grid(row=1, column=1, padx=10, pady=10)
    label_manufacturer = tk.Label(window, text=f"MANUFACTURER : {manufacturer}", font=("Arial", 15))
    label_manufacturer.grid(row=2, column=0, padx=10, pady=10)

    frame = tk.Frame(window)
    frame.grid(row=4, column=0, columnspan=2)

    label_cap_alarm = tk.Label(frame, text="ALARMING CAPACITY(%) : ", font=("Arial", 15))
    label_cap_alarm.grid(row=0, column=0, padx=10, pady=10)
    entry_cap_alarm = tk.Entry(frame, width=5, font=("Arial", 15))
    entry_cap_alarm.grid(row=0, column=1, padx=10, pady=10)
    btn_cap_alarm = tk.Button(frame, text="Start", width=10, font=("Arial", 15), command=cap_btn_click)
    btn_cap_alarm.grid(row=0, column=2, padx=10, pady=10)

    label_time_alarm = tk.Label(frame, text="ALARMING TIME(min) : ", font=("Arial", 15))
    label_time_alarm.grid(row=1, column=0, padx=10, pady=10)
    entry_time_alarm = tk.Entry(frame, width=5, font=("Arial", 15))
    entry_time_alarm.grid(row=1, column=1, padx=10, pady=10)
    btn_time_alarm = tk.Button(frame, text="Start", width=10, font=("Arial", 15), command=time_btn_click)
    btn_time_alarm.grid(row=1, column=2, padx=10, pady=10)

    note_frame = tk.Frame(window)
    note_frame.grid(row=5, column=0, columnspan=2)
    label_note = tk.Label(note_frame, text="version 1.0 | Feedback : hi@raoyi.net")
    label_note.grid(row=0, column=0, padx=10, pady=10)

    label_cap = tk.Label(window, text=f"CAPACITY : {cap}%", font=("Arial", 15))
    label_cap.grid(row=0, column=0, padx=10, pady=10)
    label_pwrst = tk.Label(window, text=f"POWER STATUS : {acst}", font=("Arial", 20))
    label_pwrst.grid(row=3, column=0, columnspan=2, padx=10, pady=10)

    # 更新全局变量以引用新创建的label
    label_cap, label_pwrst = label_cap, label_pwrst

    update_label()  # 启动第一次更新

    window.mainloop()

if __name__ == "__main__":
    create_window()